<!--
 * @Author: Dorange.Wang
 * @Date: 2021-06-09 16:46:05
 * @LastEditors: your name
 * @LastEditTime: 2021-09-28 14:55:12
 * @Description: file content
-->
<template>
  <div class="container">
    <div class="header" v-if="!disabled">
      <div class="left">
        <tree-select
          class="field-selector"
          @change="handleTreeSelect"
          placeholder="请选择显示字段"
          v-model="currentField"
          :treeData="validFields"
          :fieldMap="fieldMap"
        />
        <div class="default-symbols">
          <el-button
            v-for="symbol in symbols"
            :key="symbol"
            @click="handleSymbolClick(symbol)"
          >
            {{ symbol }}
          </el-button>
        </div>

        <el-input
          v-model="customSymbol"
          class="custom-symbol"
          placeholder="自定义分隔符"
          :maxlength="64"
          @keyup.enter.native="handleCustomSymbolOk"
        >
          <el-button
            slot="append"
            icon="el-icon-check"
            @click="handleCustomSymbolOk"
          ></el-button>
        </el-input>
      </div>

      <div v-if="clearable" class="right">
        <el-button type="text" @click="handleEmpty">
          <i class="el-icon-delete" />
          <span>清空</span>
        </el-button>
      </div>
    </div>

    <div class="content">
      <div class="value-item" v-for="(ele, index) in valueList" :key="index">
        {{ ele.label }}
        <i
          v-if="!disabled"
          class="delete-icon el-icon-circle-close del"
          @click="handleDelete(index)"
        />
      </div>
    </div>
    <div v-if="resultVisible" class="footer">
      {{ expression }}
    </div>
  </div>
</template>

<script>
const FIELD_REG = /\${\w+(\.\w+)*}/g
import { breadFirstTree } from "@/utils/util"
import { cloneDeep } from "lodash"
function getTreeNodeByFeild(tree, value, feildName = "id") {
  let treeNode = {}
  if (value) {
    breadFirstTree(
      tree,
      (node) => {
        if (node[feildName] === value) {
          treeNode = node
          return false
        }
        return true
      },
      "children"
    )
  }
  return treeNode
}
export default {
  name: "LabelExpression",

  model: {
    prop: "value",
    event: "change",
  },

  props: {
    fields: {
      // 字段列表
      type: Array,
      default: () => [],
    },
    value: {
      // 表达式
      type: String,
      default: "",
    },
    symbols: {
      // 组件使用的符号，特殊场景自行覆盖
      type: Array,
      default: () => ["+", "-", "/", "_", "[", "]"],
    },
    resultVisible: {
      // 展示输出结果
      type: Boolean,
      default: false,
    },
    disabled: {
      // 禁用 todo
      type: Boolean,
      default: false,
    },
    clearable: {
      // 清空按钮
      type: Boolean,
      default: true,
    },
  },
  data() {
    return {
      currentField: undefined, // 当前选中的字段
      valueList: [], // 选中的集合
      valueIndex: 0, // 选中值的索引 用于在表达式中间插入值
      customSymbol: "", // 自定义符号
      fieldMap: {
        children: "children",
        label: "showName",
      },
    }
  },
  computed: {
    validFields() {
      let fields = cloneDeep(this.fields)
      breadFirstTree(
        fields,
        (node) => {
          node.__value__ = "${" + node.value + "}"
          return true
        },
        "children"
      )
      return fields
    },
    expression() {
      return this.valueList.map((item) => item.value).join("")
    },
  },

  watch: {
    fields: {
      handler: "initExpression",
      immediate: true,
    },
    value: {
      handler: "initExpression",
      immediate: true,
    },
  },

  methods: {
    /**
     * 根据字段列表和表达式的解析出选中列表
     */
    initExpression() {
      if (!this.value) {
        this.valueList = []
        return false
      }

      const valueList = []
      const fields = this.value.match(FIELD_REG) || []
      const symbols = []
      let lastItem = fields.reduce((prev, cur, index, arr) => {
        let s = prev.split(cur)
        symbols.push(s[0])
        return s.slice(1).join(cur)
      }, this.value)
      symbols.push(lastItem)

      for (let i = 0; i < symbols.length; i++) {
        if (symbols[i]) {
          valueList.push({
            value: symbols[i],
            label: symbols[i],
            __type__: "SYMBOL",
          })
        }

        // 字段永远比分隔符少一个
        if (fields[i]) {
          const field = getTreeNodeByFeild(
            this.validFields,
            fields[i],
            "__value__"
          )
          if (field) {
            valueList.push({
              value: field.__value__,
              label: field.label,
              __type__: "FIELD",
            })
          } else {
            valueList.push({
              value: fields[i],
              label: fields[i],
              __type__: "SYMBOL",
            })
          }
        }
      }
      this.valueList = valueList
    },
    handleTreeSelect(value) {
      if (!value) {
        return
      }
      const field = getTreeNodeByFeild(this.validFields, value)
      this.valueList.push({
        value: field.__value__,
        label: field.label,
        __type__: "FIELD",
      })
      this.currentField = ""
      this.$emit("change", this.expression)
    },

    handleSymbolClick(value) {
      this.valueList.push({
        value,
        label: value,
        __type__: "SYMBOL",
      })
      this.$emit("change", this.expression)
    },

    handleCustomSymbolOk() {
      const symbol = this.customSymbol || ""
      this.valueList.push({
        value: symbol,
        label: symbol,
        __type__: "SYMBOL",
      })
      this.customSymbol = ""
      this.$emit("change", this.expression)
    },

    handleDelete(index) {
      this.valueList.splice(index, 1)
      this.$emit("change", this.expression)
    },

    handleEmpty() {
      this.valueList = []
      this.$emit("change", this.expression)
    },
  },
}
</script>

<style lang="scss" scoped>
.container {
  border: 1px solid #ddd;
  border-radius: 3px;
  box-sizing: border-box;

  .header {
    padding: 10px 10px 0 10px;
    display: flex;
    align-items: flex-start;
    justify-content: space-between;
    border-bottom: 1px solid #ddd;

    .left {
      width: 80%;
      display: flex;
      flex-wrap: wrap;
      .field-selector {
        width: 240px;
        margin-right: 20px;
        margin-bottom: 10px;
      }
      .default-symbols {
        margin-right: 20px;
        margin-bottom: 10px;
      }
      .custom-symbol {
        width: 240px;
        margin-bottom: 10px;
      }
    }
  }

  .content {
    $tagSize: 30px;
    $space: 10px;
    min-height: $tagSize + $space;
    padding: 10px 10px 0 10px;
    display: flex;
    flex-wrap: wrap;

    .value-item {
      display: inline-block;
      height: $tagSize - 2px;
      padding: 0 15px;
      border: 1px solid #ddd;
      line-height: $tagSize - 2px;
      border-radius: 3px;
      font-weight: bold;
      margin-right: $space;
      margin-bottom: $space;
      cursor: pointer;
      position: relative;

      .delete-icon {
        position: absolute;
        top: -6px;
        right: -6px;
        font-size: 16px;
        background: #fff;
        display: none;
      }

      &:hover .delete-icon {
        display: block;
      }
    }
  }

  .footer {
    border-top: 1px solid #ddd;
    display: flex;
    align-items: center;
    padding: 5px 10px;
  }

  .divider {
    margin: 0 20px;
  }
}
</style>
